package ru.alt22.visor.php.core.reflection;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;

import org.eclipse.core.resources.IProject;
import org.eclipse.php.internal.core.phpModel.PHPModelUtil;
import org.eclipse.php.internal.core.phpModel.phpElementData.PHPClassData;
import org.eclipse.php.internal.core.phpModel.phpElementData.PHPFunctionData;
import org.eclipse.php.internal.core.phpModel.phpElementData.PHPModifier;

public class ReflectionClass {
	private PHPClassData phpClassData;
	private IProject project;
	private ReflectionClass superclass;
	private ReflectionMethod[] methods;

	public ReflectionClass(IProject project, String className) {
		this(ReflectionUtils.findClassByName(project, className));
	}

	public ReflectionClass(PHPClassData phpClassData) {
		this.phpClassData = phpClassData;
		if (phpClassData.isUserCode()) {
			project = ReflectionUtils.getProjectFor(phpClassData);
		} else {
			project = null;
		}
	}

	public IProject getProject() {
		return project;
	}

	public PHPClassData getClassData() {
		return phpClassData;
	}

	public String getName() {
		return phpClassData.getName();
	}

	public ReflectionClass getSupertype() {
		if (null == superclass) {
			PHPClassData phpSuperclassData = PHPModelUtil.getSuperClass(phpClassData);
			if (null == phpSuperclassData) {
				return null;
			}
			this.superclass = new ReflectionClass(phpSuperclassData);
		}
		return superclass;
	}

	public ReflectionMethod[] getMethods() {
		if (null == methods) {
			Map<String, ReflectionMethod> data = new HashMap<String, ReflectionMethod>();
			ReflectionClass reflectionClass = this;
			while (null != reflectionClass) {
				PHPFunctionData[] methodsData = reflectionClass.getClassData().getFunctions();
				for (int i = 0; i < methodsData.length; i++) {
					if (null != data.get(methodsData[i].getName())) {
						continue;
					}
					data.put(methodsData[i].getName(), new ReflectionMethod(this, reflectionClass, methodsData[i]));
				}
				reflectionClass = reflectionClass.getSupertype();
			}
			methods = data.values().toArray(new ReflectionMethod[data.size()]);
			Arrays.sort(methods, new Comparator<ReflectionMethod>() {
				public int compare(ReflectionMethod arg0, ReflectionMethod arg1) {
					return arg0.getName().compareToIgnoreCase(arg1.getName());
				}
			});
		}
		return methods;
	}

	public boolean isSubClassOf(String supertypeName) {
		ReflectionClass temp = this;
		while (null != temp.getSupertype()) {
			temp = temp.getSupertype();
			if (0 == temp.getName().compareToIgnoreCase(supertypeName)) {
				return true;
			}
		}
		return false;
	}

	public boolean isSubClassOf(PHPClassData phpSuperclassData) {
		return isSubClassOf(phpSuperclassData.getName());
	}

	public boolean isInterface() {
		return PHPModifier.isInterface(phpClassData.getModifiers());
	}

	public boolean isAbstract() {
		return PHPModifier.isAbstract(phpClassData.getModifiers());
	}

	public boolean isFinal() {
		return PHPModifier.isFinal(phpClassData.getModifiers());
	}

	public boolean isInstantiable() {
		if (isInterface() || isAbstract()) {
			return false;
		}
		return true;
	}

}